package mtn.hemeshoffline.main;

import java.awt.Color;
import java.io.File;
import java.io.PrintWriter;

import mtn.sunflow.SunFlowAPIAPI;
import org.sunflow.math.Vector3;
import peasy.PeasyCam;
import processing.core.PApplet;
import wblut.geom.core.WB_Point3d;
import wblut.hemesh.core.HE_Mesh;
import wblut.hemesh.creators.HEC_Creator;
import wblut.hemesh.creators.HEC_Sphere;
import wblut.core.processing.*;
import oscP5.*;
import netP5.*;

public class Main extends PApplet {

	WB_Render render;
	HEC_Creator creator;
	HE_Mesh myShape;
	PrintWriter output;
	// PeasyCam cam;
	int bgcolor = color(230, 230, 230);
	int shapecolor = color(200, 10, 100);
	int myWidth = 200; // sketch width
	int myHeight = 200; // sketch height
	float actualZoom = 20;
	boolean enableRendering = false; // output via sunflow

	OscP5 oscP5;
	int value1;
	int value2;
	String[] lines;
	int index = 0;

	public final static int READMODE = 1;
	public final static int WRITEMODE = 2;
	// Change this mode to switch between reading from and writing data to disk
	int mode = READMODE;

	public void setup() {
		size(myWidth, myHeight, OPENGL);
		render = new WB_Render(this);
		creator = new HEC_Sphere().setRadius(200).setUFacets(7).setVFacets(7).setCenter(0, 0, 0);
		myShape = new HE_Mesh(creator);
		oscP5 = new OscP5(this, 7400);

		if (mode == READMODE) {
			lines = loadStrings(File.separatorChar + "data" + File.separatorChar + "output.txt");
			System.out.println(lines.length);
			enableRendering = true;
		} else if (mode == WRITEMODE)
			output = createWriter(File.separatorChar + "data" + File.separatorChar + "output.txt");

		// cam = new PeasyCam(this, 2000);
	}

	public void draw() {
		if (mode == READMODE) {
			// Before we do anything else, read the current frame's data from
			// disk
			if (index < lines.length) {
				String[] pieces = split(lines[index], '\t');
				if (pieces.length == 3) {
					// This code assumes the data is in the format of:
					// framecount\tvalue1\t value2
					value1 = Integer.parseInt(pieces[1]);
					value2 = Integer.parseInt(pieces[2]);
				}
				// Go to the next line for the next run through draw()
				index = index + 1;
			}
		}

		background(0, 0, 0);
		// shapecolor = color(random(255),random(255),random(255));
		myShape.rotateAboutAxis(PApplet.radians(value1), new WB_Point3d(0, 1, 0), new WB_Point3d(0, 0, 0));
		myShape.rotateAboutAxis(PApplet.radians(value2), new WB_Point3d(1, 0, 0), new WB_Point3d(0, 0, 0));
		fill(shapecolor);
		stroke(0);
		this.camera(0, 0, 400, 0, 0, 0, 0, 1, 0);

		render.drawFaces(myShape);
		render.drawEdges(myShape);
		if (enableRendering) {
			hemeshToSunflow();
			sunflow();
		}

		if (mode == WRITEMODE)
			output.println(frameCount + "\t" + value1 + "\t" + value2);
	}

	public void oscEvent(OscMessage msg) {
		if (mode == WRITEMODE) {
			if (msg.addrPattern().equals("/value1")) {
				value1 = msg.get(0).intValue();
			} else if (msg.addrPattern().equals("/value2")) {
				value2 = msg.get(0).intValue();
			}
		}
	}

	public static void main(String args[]) {
		PApplet.main(new String[] { "mtn.hemeshoffline.main.Main" });
	}

	public void keyPressed() {
		if (mode == WRITEMODE) {
			// Uncomment this and press a key to finish writing the output file
			output.flush();
			output.close();
		}
	}

	float[] verticesHemeshOneDim;
	int[] facesHemeshOneDim;

	// convert hemeshShape into sunflow-ready arrays
	void hemeshToSunflow() {

		// for accurate rendering the rotatation is processed into the shape
		// (temporarily)
		/*
		 * myShape.rotateAboutAxis(radians(0), 0,0,0, 0,1,0); // //Rotation
		 * around Y axis myShape.rotateAboutAxis(radians(0), 0,0,0, 1,0,0); //
		 * // Rotation around X axis
		 */
		myShape.validate(false, true);
		myShape.triangulate();

		float[][] verticesHemesh = myShape.getVerticesAsFloat();
		verticesHemeshOneDim = new float[verticesHemesh.length * 3];

		int[][] facesHemesh = myShape.getFacesAsInt();
		facesHemeshOneDim = new int[facesHemesh.length * 3];

		int hemeshCounter = 0;

		for (int y = 0; y < verticesHemesh.length; y++) {
			for (int x = 0; x < 3; x++) {
				// for accurate rendering of the x & y position the translate
				// values are processed into the sunflow coordinates
				if (x == 0) {
					verticesHemeshOneDim[hemeshCounter] = verticesHemesh[y][x] + (0 - width / 2) / actualZoom;
				} else if (x == 1) {
					verticesHemeshOneDim[hemeshCounter] = -verticesHemesh[y][x] - (0 - height / 2) / actualZoom;
				} else {
					verticesHemeshOneDim[hemeshCounter] = verticesHemesh[y][x];
				}
				hemeshCounter++;
			}
		}

		hemeshCounter = 0;

		for (int y = 0; y < facesHemesh.length; y++) {
			for (int x = 0; x < 3; x++) {
				facesHemeshOneDim[hemeshCounter] = facesHemesh[y][x];
				hemeshCounter++;
			}
		}
	}

	// render shape in sunflow
	void sunflow() {
		SunFlowAPIAPI sunflow = new SunFlowAPIAPI();
		sunflow.setWidth(myWidth);
		sunflow.setHeight(myHeight);
		int samples;

		if (enableRendering) {
			sunflow.setAaMin(0);
			sunflow.setAaMax(2);
			samples = 16;
		} else {
			sunflow.setAaMin(1);
			sunflow.setAaMax(2);
			samples = 24;
		}

		sunflow.setThinlensCamera("thinLensCamera", 50f, (float) myWidth / myHeight);
		sunflow.setCameraPosition(0, 0, 400f);
		sunflow.setCameraTarget(0, 0, 0);

		sunflow.setShinyDiffuseShader("myShinyShader", new Color(shapecolor), .25f);
		sunflow.drawMesh("myHemesh", verticesHemeshOneDim, facesHemeshOneDim, actualZoom / 20, 0, 0, 0);

		if (enableRendering) {
			sunflow.setSunSkyLight("mySunSkyLight", new Vector3(0, 1, 0), new Vector3(1, 0, 0), new Vector3(-0.15f, 0.2f, -0.2f), new Color(bgcolor), samples, 1.2f, true);
			sunflow.setAmbientOcclusionEngine(new Color(255), new Color(0), samples, 7.5f);
			sunflow.render(sketchPath + "/output/sunflow/Sunflow_" + nf(frameCount, 4) + ".png");
		}
	}

	// createHemesh(); // to reset the shape's rotation (which was internalised
	// into the shape temporarily for sunflow rendering)
}
